/*
 * @Descripttion: 改造版本librtmp推流器（支持265 codecID=12）
 * @version: 
 * @Author: HuangJunren
 * @Date: 2020-07-29 11:32:14
 * @LastEditors: HuangJunren
 * @LastEditTime: 2020-08-05 11:49:28
 */

#include "RtmpWriter.h"
#include "UtilRtmp.h"	
#include <stdio.h>	
#include "Log.h"
#include "Sps.h"	

RtmpWriter::RtmpWriter()	
{	
    _isWaitKeyframe = true;	
    _frameType = 0;	
    _startVTime = 0;	
    _startATime = 0;
}	
RtmpWriter::~RtmpWriter()	
{	
    if (_rtmp) {	
        RTMP_Close(_rtmp);	
        RTMP_Free(_rtmp);	
        _rtmp = NULL;	
    }	
    _isWaitKeyframe = true;	
    _frameType = 0;	
    _startATime = 0;	
    _startVTime = 0;	
    //_g726ToAac.uinit();	
}	

const char* RtmpWriter::errorMsg()	
{	
    return _errMsg;	
}	

int RtmpWriter::errorCode()	
{	
    return _errCode;	
}	

// int RtmpWriter::Send_On_metadata(){
//     RTMPPacket packet={0};  
//     uint8_t rtmp_buffer[2048];

//     memset(&packet,0,sizeof(RTMPPacket));  
//     packet.m_nChannel = 0x04;  
//     packet.m_headerType = RTMP_PACKET_SIZE_LARGE;  
//     packet.m_nTimeStamp = 0;  
//     packet.m_nInfoField2 = hRtmp->rtmp->m_stream_id;  
//     packet.m_hasAbsTimestamp = 0;  
//     packet.m_body =(char *) rtmp_buffer;  
//     char * szTmp=(char *)rtmp_buffer;  
//     packet.m_packetType = RTMP_PACKET_TYPE_INFO;  
//     szTmp=put_byte(szTmp, AMF_STRING );  
//     szTmp=put_amf_string(szTmp, "@setDataFrame" );  
//     szTmp=put_byte(szTmp, AMF_STRING );  
//     szTmp=put_amf_string(szTmp, "onMetaData" );  
//     szTmp=put_byte(szTmp, AMF_OBJECT );  
//     szTmp=put_amf_string( szTmp, "author" );  
//     szTmp=put_byte(szTmp, AMF_STRING );  
//     szTmp=put_amf_string( szTmp, "" );  
//     szTmp=put_amf_string( szTmp, "copyright" );  
//     szTmp=put_byte(szTmp, AMF_STRING );  
//     szTmp=put_amf_string( szTmp, "" );  
//     szTmp=put_amf_string( szTmp, "description" );  
//     szTmp=put_byte(szTmp, AMF_STRING );  
//     szTmp=put_amf_string( szTmp, "" );  
//     szTmp=put_amf_string( szTmp, "keywords" );  
//     szTmp=put_byte(szTmp, AMF_STRING );  
//     szTmp=put_amf_string( szTmp, "" );  
//     szTmp=put_amf_string( szTmp, "rating" );  
//     szTmp=put_byte(szTmp, AMF_STRING );  
//     szTmp=put_amf_string( szTmp, "" );  
//     szTmp=put_amf_string( szTmp, "presetname" );  
//     szTmp=put_byte(szTmp, AMF_STRING );  
//     szTmp=put_amf_string( szTmp, "Custom" );  
//     szTmp=put_amf_string( szTmp, "width" );  
//     szTmp=put_amf_double( szTmp, 640.0 );//p264Param->i_width );  
//     szTmp=put_amf_string( szTmp, "width" );  
//     szTmp=put_amf_double( szTmp, 640.0 );//p264Param->i_width );  
//     szTmp=put_amf_string( szTmp, "height" );  
//     szTmp=put_amf_double( szTmp, 480.0 );//p264Param->i_height );  
//     szTmp=put_amf_string( szTmp, "framerate" );  
//     szTmp=put_amf_double( szTmp, 25.0 );//(double)p264Param->i_fps_num / p264Param->i_fps_den );  
//     szTmp=put_amf_string( szTmp, "videocodecid" );  
//     szTmp=put_byte(szTmp, AMF_STRING );  
//     szTmp=put_amf_string( szTmp, "avc1" );  
//     szTmp=put_amf_string( szTmp, "videodatarate" );  
//     szTmp=put_amf_double( szTmp, 1500.0 );//p264Param->rc.i_bitrate );   
//     szTmp=put_amf_string( szTmp, "avclevel" ); 

//     szTmp=put_amf_double( szTmp, 1.0 );//p264Param->i_level_idc );   
//     szTmp=put_amf_string( szTmp, "avcprofile" );  
//     szTmp=put_amf_double( szTmp, 0x42 );   
//     szTmp=put_amf_string( szTmp, "videokeyframe_frequency" );  
//     szTmp=put_amf_double( szTmp, 8.0 );   
//     szTmp=put_amf_string( szTmp, "" );  
//     szTmp=put_byte( szTmp, AMF_OBJECT_END );  
//     packet.m_nBodySize=szTmp-(char *)rtmp_buffer;  

//     printf( "sending %d as header\n", packet.m_nBodySize );

//     hex_dump_internal( packet.m_body, packet.m_nBodySize );

//     RTMP_SendPacket(hRtmp->rtmp,&packet,1);  
// }

bool RtmpWriter::initUrl(const char* url)	
{	
    LOG("%s\n", url);	
    do {	
        _rtmp = RTMP_Alloc();	
        RTMP_Init(_rtmp);	
        // set connection timeout,default 30s	
        if (!RTMP_SetupURL(_rtmp, ( char* )url)) {	
            _errMsg = "SetupURL Error";	
            break;	
        }	
        //	
        RTMP_EnableWrite(_rtmp);	
        if (0 == RTMP_Connect(_rtmp, NULL)) {	
            _errMsg = "Connect Server Error";	
            break;	
        }	
        //连接流	
        if (0 == RTMP_ConnectStream(_rtmp, 0)) {	
            _errMsg = "Connect Stream Error";	
            RTMP_Close(_rtmp);	
            break;	
        }	
        RTMP_LogSetLevel(RTMP_LOGCRIT);  //不显示打印日志	
        // _fpName = url;	
        // std::string::size_type m = _fpName.rfind("/", _fpName.length());	
        // std::string            devID = &_fpName.at(( int )m + 1);	
        // _g726Writer.initfp((devID.append(".g726").c_str()));	
        // _mp4Writer.fpname(devID.c_str());	
        return true;	
    } while (0);	
    RTMP_Free(_rtmp);	
    _rtmp = NULL;	
    return false;	
}	

/**
 * @name: publishVideoframe
 * @msg: 265推流方法
 * @param 
 *      char* frame：封装好的265-ES-Packet包（封装过程见：ESTOES）；
 *      int len：封装好的265-ES-Packet包的长度；
 *      int type：I-frame=》0x01，P-frame=》0x00
 *      pts：封装好的265-ES-Packet包时计算出的pts
 * @return {type} 
 */
int RtmpWriter::publishVideoframe(char* frame, int len, int type, unsigned long long pts)	
{	
    //解出原始的nalu包的数组和一个帧中nalu包的个数
    std::vector<std::string> naluVec = ParseNalUnit(frame, len);	
    int                      naluSize = naluVec.size();	

    if (naluSize < 0) {	
        return -1;	
    }	
    // 关键帧	
    if (_isWaitKeyframe && type == 0x01) {	
        unsigned char type = frame[4] & 0x1F;	
        // 0x01 slice 0x05 idr 0x06 sei 0x07 sps 0x08 pps	
        switch (type) {	
        case avc::NALU_TYPE_IDR:	
        case avc::NALU_TYPE_SPS:	
        case avc::NALU_TYPE_PPS:	
        case avc::NALU_TYPE_SLICE:	
        case avc::NALU_TYPE_SEI:	
            _frameType = VFRAME_TYPE_ID_H264;	
            _publishFunc = Send264Videoframe;	
            break;	
        default:	
            _frameType = VFRAME_TYPE_ID_HEVC;	
            _publishFunc = Send265Videoframe;	
            break;	
        }	
        _startVTime = pts;	
        _isWaitKeyframe = false;	
    }
	
    if (_frameType == 0) {	
        return -1;	
    }	
    
    //判断推送流是否与预制格式一致,不一致返回
    if(type == 0x01) {	
        unsigned char type = frame[4] & 0x1F;	
        int frameType = -1;
        // 0x01 slice 0x05 idr 0x06 sei 0x07 sps 0x08 pps	
        switch (type) {	
            case avc::NALU_TYPE_IDR:	
            case avc::NALU_TYPE_SPS:	
            case avc::NALU_TYPE_PPS:	
            case avc::NALU_TYPE_SLICE:	
            case avc::NALU_TYPE_SEI:	
                frameType = VFRAME_TYPE_ID_H264;	
                break;	
            default:	
                frameType = VFRAME_TYPE_ID_HEVC;	
                break;	
        }

        if(frameType != _frameType){
            return -1;
        }
    }	

    // _mp4Writer.writeVideoframe(frame, len, type, pts);	
    //uint32_t dts = (pts - _startVTime) / 1000;    // 此处的pts计算为原始的计算方法
    uint32_t dts = (pts - _startVTime);     
    for (int i = 0; i < naluSize; i++) {	
        _publishFunc(_rtmp, naluVec[i], dts);
    }

    return 0;	
}	

// 发送AAC RTMP包	
// 可以参考 http://billhoo.blog.51cto.com/2337751/1557646/	
void RtmpWriter::publishAudioframe(char* frame, int len, unsigned long long pts)	
{	
    // //_mp4Writer.writeAudioframe(frame, len, pts);	
    // if (_startATime == 0) {	
    //     _startATime = pts;	
    //     _g726ToAac.init();	
    // }	
    // // _g726Writer.write(frame, len);	
    // int            aacLen = 0;	
    // unsigned char* aac = _g726ToAac.toAacEncodec(frame, len, aacLen);	
    // if (aacLen == 0) {	
    //     return;	
    // }	
    // uint32_t    dts = (pts - _startATime) / 1000;	
    // static bool isSeedSpecialInfo = false;	
    // if (!isSeedSpecialInfo) {	
    //     int            specialLen = 0;	
    //     unsigned char* pSpecialData = _g726ToAac.aacSpecialData(&specialLen);	
    //     SendAccAudioframe(_rtmp, pSpecialData, specialLen, dts, false);	
    //     isSeedSpecialInfo = true;	
    // }	
    // SendAccAudioframe(_rtmp, aac, aacLen, dts);	
}	